package com.dubbo.framework.proxy;

import cn.hutool.core.collection.CollUtil;
import com.dubbo.framework.Invocation;
import com.dubbo.framework.URL;
import com.dubbo.framework.balance.LoadBalance;
import com.dubbo.framework.balance.RandomLoadBalance;
import com.dubbo.framework.config.ServerConfig;
import com.dubbo.framework.protocol.Protocol;
import com.dubbo.framework.protocol.ProtocolFactory;
import com.dubbo.framework.protocol.http.HttpClient;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import static com.dubbo.framework.consts.DubboConstant.ZK_LIST_CACHE;

/**
 * 动态代理工厂类
 * 使用JDK动态代理
 *
 * @author by Mr. Li 2021/4/29 10:27
 */
@Slf4j
public class ProxyFactory {

    public final static ConcurrentHashMap<String, List<URL>> listCONCURRENT_HASH_MAP = new ConcurrentHashMap<>();

    /**
     * 动态代理 远程调用
     *
     * @param interfaceClass 接口类
     * @param <T>            返回类型
     * @return T
     */
    @SuppressWarnings("unchecked")
    public static <T> T getProxy(final Class<?> interfaceClass) {
        return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //HttpClient httpClient = new HttpClient();

                // 使用工厂类 决定协议参数
                final Protocol protocol = ProtocolFactory.getProtocol();

                Invocation invocation = new Invocation(interfaceClass.getName(),
                        method.getName(), method.getParameterTypes(), args);

                // 调用远程读物 负载均衡获取服务
                LoadBalance loadBalance = new RandomLoadBalance();
                // 做本地缓存，并且添加zookeeper watcher机制，实时更新本地数据
                if (CollUtil.isEmpty(listCONCURRENT_HASH_MAP)) {
                    final List<URL> pull = ServerConfig.pull();
                    listCONCURRENT_HASH_MAP.put(ZK_LIST_CACHE, pull);
                }

                final URL load = loadBalance.load(listCONCURRENT_HASH_MAP.get(ZK_LIST_CACHE));
                log.info("远程调用的服务：ip:{}，port:{}", load.getIpAddr(), load.getPort());

                // 发送远程调用
                return protocol.send(load, invocation);
            }
        });

    }
}
